package com.dog.basics.admin.security;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.dog.basics.bean.model.sys.SysMenu;
import com.dog.basics.bean.model.sys.SysRole;
import com.dog.basics.bean.model.sys.SysUser;
import com.dog.basics.bean.vo.admin.sys.AdminSysRoleVo;
import com.dog.basics.bean.vo.admin.sys.SysUserPageVo;
import com.dog.basics.common.constant.CommonConstants;
import com.dog.basics.common.util.CacheManagerUtil;
import com.dog.basics.constant.Constant;
import com.dog.basics.dao.sys.SysMenuMapper;
import com.dog.basics.dao.sys.SysRoleMapper;
import com.dog.basics.dao.sys.SysUserMapper;
import com.dog.basics.security.enums.App;
import com.dog.basics.security.exception.UsernameNotFoundExceptionBase;
import com.dog.basics.security.service.DogSysUser;
import com.dog.basics.security.service.DogUser;
import com.dog.basics.security.service.DogUserDetailsService;
import com.dog.basics.security.util.SecurityUtils;
import com.dog.basics.service.sys.SysUserService;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.PatternMatchUtils;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;


/**
 * 用户详细信息
 *
 * @author
 */
@Slf4j
@Service
@AllArgsConstructor
public class DogSysUserDetailsServiceImpl implements DogUserDetailsService {
    private final SysMenuMapper sysMenuMapper;
    private final SysUserService sysUserService;
    private final SysRoleMapper sysRoleMapper;
    private final CacheManagerUtil cacheManagerUtil;
    private final SysUserMapper sysUserMapper;

    /**
     * 用户密码登录
     *
     * @param username 用户名(登录名)
     * @return
     * @throws UsernameNotFoundExceptionBase
     */
    @Override
    @SneakyThrows
    public DogSysUser loadUserByUsername(String username) {
        return getUserDetails(username);
    }


    /**
     * 构建userdetails
     *
     * @param username 用户名称
     * @return
     */
    private DogSysUser getUserDetails(String username) {
        SysUserPageVo sysUser = sysUserService.getSysUserByUserName(username);

        if (sysUser == null) {
            throw new UsernameNotFoundExceptionBase("common.noData");
        }
        Collection<? extends GrantedAuthority> authorities = AuthorityUtils.createAuthorityList(getUserPermissions(sysUser.getUserId()).toArray(new String[0]));
        boolean finalHasRole = authorities.stream().map(GrantedAuthority::getAuthority).filter(StringUtils::hasText).anyMatch(x -> PatternMatchUtils.simpleMatch(
                StrUtil.format("{}{}", CommonConstants.ROLE_PREFIX, CommonConstants.ROLE_AGENT_CODE), x));
        Integer type  = 0;
        if (finalHasRole){
            type = 1;
        }else if(
        authorities.stream().map(GrantedAuthority::getAuthority).filter(StringUtils::hasText).anyMatch(x -> PatternMatchUtils.simpleMatch(
                StrUtil.format("{}{}", CommonConstants.ROLE_PREFIX, CommonConstants.ROLE_FIELD_CODE), x))
        ) {
            type = 2;
        }
        // 构造security用户
        DogSysUser sysUser1 = new DogSysUser(sysUser.getUserId(), sysUser.getSfPassword(), sysUser.getUsername(), sysUser.getPassword(), sysUser.getStatus() == 0,
                true, true, true, authorities);
        sysUser1.setAccountType(type);
        return sysUser1;


    }

    private Set<String> getUserPermissions(Long userId) {
        List<String> permsList = CollUtil.newArrayList("-1");

        //系统管理员，拥有最高权限
        if (userId == Constant.SUPER_ADMIN_ID) {
            // 查询角色
            List<SysRole> roles = sysRoleMapper.selectList(Wrappers.<SysRole>lambdaQuery().eq(SysRole::getRoleCode, CommonConstants.ROLE_ADMIN_CODE));
            permsList.addAll(roles.stream().map(e -> StrUtil.format("{}{}", CommonConstants.ROLE_PREFIX, e.getRoleCode())).collect(Collectors.toList()));
            // 查询权标
            List<SysMenu> menuList = sysMenuMapper.selectList(Wrappers.emptyWrapper());
            permsList.addAll(menuList.stream().map(SysMenu::getPermission).collect(Collectors.toList()));
        } else {
            List<AdminSysRoleVo> roleList = sysRoleMapper.listRolesByUserId(userId);
            List<Long> roleIds = roleList.stream().map(e -> e.getRoleId()).distinct().collect(Collectors.toList());
            if (CollUtil.isEmpty(roleIds)) {
                roleIds.add(-2L);
            }
            // 查询角色
            List<SysRole> roles = sysRoleMapper.selectList(Wrappers.<SysRole>lambdaQuery().in(SysRole::getRoleId, roleIds));
            permsList.addAll(roles.stream().map(e -> StrUtil.format("{}{}", CommonConstants.ROLE_PREFIX, e.getRoleCode())).collect(Collectors.toList()));
            // 查询权标
            permsList.addAll(sysUserMapper.queryAllPerms(userId));
        }
        Set<String> permsSet = permsList.stream().flatMap((perms) -> {
                    if (StrUtil.isBlank(perms)) {
                        return null;
                    }
                    return Arrays.stream(perms.trim().split(","));
                }
        ).collect(Collectors.toSet());
        return permsSet;
    }

    @Override
    public DogUser loadUserByAppIdAndBizUserId(App app, String bizUserId) {
        return null;
    }

    @Override
    public DogUser loadUserBypasswordOrEmail(String code) {
        return null;
    }

    @Override
    public void insertUserIfNecessary(String phone, String openId, Integer type) {
    }

    @Override
    public void updateUser(Long userId) {

    }

    /**
     * 更新登录的时间和IP 后台
     *
     * @param userId
     */
    @Override
    public Boolean updateSysUser(Long userId) {
        SysUser sysUser = sysUserService.getById(userId);
        Validator.validateNotNull(sysUser, "common.noData!");
        sysUser.setLoginTime(DateUtil.currentSeconds());
        Validator.validateTrue(sysUserService.updateById(sysUser),"common.edit");
        return Boolean.TRUE;
    }

}
